package com.hello.auth.controller;

import com.hello.auth.form.LoginBody;
import com.hello.auth.form.RegisterBody;
import com.hello.auth.form.WxLoginBody;
import com.hello.auth.service.SysLoginService;
import com.hello.common.core.constant.SecurityConstants;
import com.hello.common.core.domain.R;
import com.hello.common.core.utils.JwtUtils;
import com.hello.common.core.utils.StringUtils;
import com.hello.common.security.auth.AuthUtil;
import com.hello.common.security.service.TokenService;
import com.hello.common.security.utils.SecurityUtils;
import com.hello.system.api.RemoteUserService;
import com.hello.system.api.model.LoginUser;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.util.Map;


/**
 * token 控制
 * 
 * @author hello
 */
@Slf4j
@RestController
@RequiredArgsConstructor
public class TokenController
{
    private final TokenService tokenService;
    private final SysLoginService sysLoginService;
    private final RemoteUserService remoteUserService;

    @PostMapping("login")
    public R<?> login(@RequestBody LoginBody form)
    {
        log.info("用户登录请求: {}", form.getUsername());
        // 用户登录
        LoginUser userInfo = sysLoginService.login(form.getUsername(), form.getPassword());
        // 获取登录token
        return R.ok(tokenService.createToken(userInfo));
    }

    @DeleteMapping("logout")
    public R<?> logout(HttpServletRequest request)
    {
        String token = SecurityUtils.getToken(request);
        if (StringUtils.isNotEmpty(token))
        {
            String username = JwtUtils.getUserName(token);
            log.info("用户退出登录: {}", username);
            // 删除用户缓存记录
            AuthUtil.logoutByToken(token);
            // 记录用户退出日志
            sysLoginService.logout(username);
        }
        return R.ok();
    }

    @PostMapping("refresh")
    public R<?> refresh(HttpServletRequest request)
    {
        LoginUser loginUser = tokenService.getLoginUser(request);
        if (StringUtils.isNotNull(loginUser))
        {
            log.debug("刷新令牌: {}", loginUser.getUsername());
            // 刷新令牌有效期
            tokenService.refreshToken(loginUser);
            return R.ok();
        }
        return R.ok();
    }

    @PostMapping("register")
    public R<?> register(@RequestBody RegisterBody registerBody)
    {
        log.info("用户注册: {}", registerBody.getUsername());
        // 用户注册
        sysLoginService.register(registerBody.getUsername(), registerBody.getPassword());
        return R.ok();
    }
    
    @PostMapping("wx-register")
    public R<?> wxRegister(@RequestBody RegisterBody registerBody)
    {
        log.info("微信用户注册: {}, code: {}", registerBody.getUsername(), registerBody.getCode());
        
        // 用户名和密码校验
        if (StringUtils.isEmpty(registerBody.getUsername()) || 
            StringUtils.isEmpty(registerBody.getPassword()) ||
            StringUtils.isEmpty(registerBody.getConfirmPassword())) {
            return R.fail("用户名和密码不能为空");
        }
        
        // 密码一致性校验
        if (!registerBody.getPassword().equals(registerBody.getConfirmPassword())) {
            return R.fail("两次输入的密码不一致");
        }
        
        try {
            // 先获取微信openid，检查code是否有效
            Map<String, Object> wxInfo = sysLoginService.getWxOpenid(registerBody.getCode());
            
            // 检查是否返回了错误信息
            if (wxInfo != null && wxInfo.containsKey("errcode")) {
                Integer errcode = (Integer) wxInfo.get("errcode");
                String errmsg = (String) wxInfo.get("errmsg");
                
                log.error("微信接口返回错误，错误码: {}, 错误信息: {}", errcode, errmsg);
                
                // 特殊处理code已使用的错误
                if (errcode != null && errcode == 40163) {
                    return R.fail("微信登录凭证已失效，每个凭证只能使用一次，请重新获取新的登录凭证");
                }
                
                return R.fail("微信接口错误: " + errmsg);
            }
            
            if (wxInfo == null || !wxInfo.containsKey("openid")) {
                log.error("微信用户注册失败，无法获取openid");
                return R.fail("微信用户注册失败，无法获取用户信息");
            }
            
            String openid = (String) wxInfo.get("openid");
            log.info("获取微信openid成功: {}", openid);
            
            // 检查该openid是否已绑定其他用户
            R<LoginUser> userCheckResult = remoteUserService.getUserInfoByWxOpenid(openid, SecurityConstants.INNER);
            if (userCheckResult.getCode() == R.SUCCESS && userCheckResult.getData() != null) {
                log.error("该微信账号已绑定用户: {}", userCheckResult.getData().getUsername());
                return R.fail("该微信账号已绑定其他用户，请使用其他微信账号注册");
            }
            
            // 注册用户
            sysLoginService.register(registerBody.getUsername(), registerBody.getPassword());
            log.info("微信用户注册成功，用户名: {}, openid: {}", registerBody.getUsername(), openid);
            
            // 调用远程服务绑定openid和用户
            R<Boolean> bindResult = sysLoginService.bindWxOpenid(registerBody.getUsername(), openid);
            
            if (bindResult.getCode() == R.FAIL) {
                log.error("关联微信账号失败: {}", bindResult.getMsg());
                return R.fail("注册成功但关联微信账号失败: " + bindResult.getMsg());
            }
            
            return R.ok("微信用户注册成功");
        } catch (Exception e) {
            log.error("微信用户注册异常", e);
            
            // 检查异常信息中是否包含code已使用错误
            if (e.getMessage() != null && e.getMessage().contains("code been used")) {
                return R.fail("微信登录凭证已失效，每个凭证只能使用一次，请重新获取新的登录凭证");
            }
            
            return R.fail(e.getMessage());
        }
    }
    
    @PostMapping("wx-login")
    public R<?> wxLogin(@RequestBody WxLoginBody form)
    {
        log.info("微信小程序登录请求，code: {}", form.getCode());
        // 微信登录
        LoginUser userInfo = sysLoginService.wxLogin(form.getCode());
        // 获取登录token
        return R.ok(tokenService.createToken(userInfo));
    }

    /**
     * 获取微信OpenID (POST方式)
     */
    @PostMapping("wx-openid")
    public R<?> postWxOpenid(@RequestBody WxLoginBody form)
    {
        log.info("POST方式获取微信OpenID请求, code: [{}], 长度: {}", form.getCode(), form.getCode().length());
        
        // 调用service获取微信openid
        Map<String, Object> wxInfo = sysLoginService.getWxOpenid(form.getCode());
        
        log.info("获取微信OpenID成功: {}", wxInfo);
        return R.ok(wxInfo);
    }
    
    /**
     * 获取微信OpenID (GET方式)
     */
    @GetMapping("wx-openid")
    public R<?> getWxOpenid(@RequestParam String code)
    {
        log.info("GET方式获取微信OpenID请求, code: [{}], 长度: {}", code, code.length());
        
        // 调用service获取微信openid
        Map<String, Object> wxInfo = sysLoginService.getWxOpenid(code);
        
        log.info("获取微信OpenID成功: {}", wxInfo);
        return R.ok(wxInfo);
    }
    
    /**
     * 通过微信服务获取OpenID (v2版本)
     * 此接口使用微信服务专用接口获取openid
     */
    @PostMapping("wx-openid-v2")
    public R<?> getWxOpenidV2(@RequestBody WxLoginBody form)
    {
        log.info("V2版本获取微信OpenID请求, code: [{}], 长度: {}", form.getCode(), form.getCode().length());
        
        // 调用service获取微信openid (使用新的微信服务接口)
        Map<String, Object> wxInfo = sysLoginService.getWxOpenid(form.getCode());
        
        log.info("V2版本获取微信OpenID成功: {}", wxInfo);
        return R.ok(wxInfo);
    }
    
    /**
     * 绑定微信OpenID到用户
     */
    @PostMapping("bind-wx-openid")
    public R<?> bindWxOpenid(@RequestBody Map<String, String> params)
    {
        String username = params.get("username");
        String openid = params.get("openid");
        
        log.info("绑定微信OpenID请求, username: {}, openid: {}", username, openid);
        
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(openid)) {
            return R.fail("用户名和微信OpenID不能为空");
        }
        
        R<Boolean> result = sysLoginService.bindWxOpenid(username, openid);
        
        if (result.getCode() == R.FAIL) {
            log.error("绑定微信OpenID失败: {}", result.getMsg());
            return result;
        }
        
        return R.ok(true, "绑定成功");
    }
}
